package com.webserver.core;

import com.webserver.annotations.Controller;
import com.webserver.annotations.RequestMapping;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

/**
 * 该类用于保存所有处理业务的Controller以及对应方法和请求
 */
public class HandlerMapping {
    /**
     * 保存每一个请求以及处理该请求的业务类及方法
     * key：请求路径
     * value：处理该请求的业务类实例及方法
     * key：请求路径
     * value:处理该请求的业务类实例及方法
     * 例如：
     * key：“/myweb/reguser”
     * value:MethodMapping{
     *      Object controller==>UserController实例
     *      Method method ==》reg()方法
     * }
     */
    private static Map<String,MethodMapping> mapping =new HashMap<>();
    static {
        try {
            initMapping();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void initMapping() throws URISyntaxException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        File dir = new File(
                HandlerMapping.class.getClassLoader().getResource(
                        "com/webserver/controllers"
                ).toURI()
        );
        File[] subs = dir.listFiles(f->!f.getName().contains("$")&&f.getName().endsWith(".class"));

        for(File sub : subs){
            String fileName = sub.getName();
            String className = fileName.substring(0,fileName.indexOf("."));
            Class cls = Class.forName("com.webserver.controllers."+className);
            //判断是否含有注解@Controller
            if(cls.isAnnotationPresent(Controller.class)){
                //实例化该Controller
                Object controller = cls.newInstance();
                //获取其定义的所有方法
                Method[] methods = cls.getDeclaredMethods();
                for(Method method : methods){
                    //判断该方法是否含有注解RequestMapping
                    if(method.isAnnotationPresent(RequestMapping.class)){
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        String path = requestMapping.value();

                        //将Controller对象与处理该请求的方法组成一个MethodMapping
                        MethodMapping methodMapping = new MethodMapping(controller,method);
                        mapping.put(path,methodMapping);
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        System.out.println(mapping);
    }

    /**
     * 根据给定的路径获取对应的处理类及方法
     * 若给定的路径不对应业务则返回值为null
     * @param path
     * @return
     */
    public static MethodMapping getMethodByPath(String path){
        return mapping.get(path);
    }
    /**
     * 该类的每一个实例用于保存一个处理业务的方法以及该方法所属的某Controller对象
     * ，以便使用反射调用该方法
     */
       public static class MethodMapping{
           private Object controller;
           private Method method;

        public MethodMapping(Object controller, Method method) {
            this.controller = controller;
            this.method = method;
        }

        public Object getController() {
            return controller;
        }

        public void setController(Object controller) {
            this.controller = controller;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }
    }

}
